
using namespace std;

class Base {
    friend class Pal;                   // Pal 在访问 Base 的派生类时不具有特殊性
    public:
        void pub_mem() {}               // public 成员
    protected:
        int prot_mem;                   // protected 成员
    private:
        char priv_mem;                  // private 成员
};

class Sneaky : public Base {
    friend void clobber(Sneaky&);       // 能访问 Sneaky::prot_mem
    // friend void clobber(Base&);      // 不能访问 Base::prot_mem
    int j;                              // j 默认是 private
};

class Pal {
    public:
        int f(Base b) { return b.prot_mem; }    // 正确：Pal 是 Base 的友元
        // int f2(Sneaky s) { return s.j; }     // 错误：Pal 不是 Sneaky 的友元
        // 对基类的访问权限由基类本身控制，即使对于派生类的基类部分也是如此
        int f3(Sneaky s) { return s.prot_mem; } // 正确：Pal 是 Base 的友元
};

// D2 对 Base 的 protected 和 private 成员不具有特殊的访问能力
class D2 : public Pal {
    public:
        // int mem(Base b) { return b.prot_mem; }  // 错误：友元关系不能继承
};

class Derived : private Base {
    // 使用了私有继承，继承的成员 pub_mem 和 prot_mem 在默认情况下是 Derived 的私有成员
    // 使用 using 声明语句来改变这些成员的可访问性
    // 派生类只能为它可以访问的成员提供 using 声明
    public:
        // 保持对象尺寸相关的成员的访问级别
        using Base::pub_mem;
    protected:
        using Base::prot_mem;
};

/**
 * struct 与 class 的主要区别：
 * struct   成员访问说明符、派生访问说明符默认为 public
 * class    成员访问说明符、派生访问说明符默认为 private
 */
struct D3 : Base { };       // 默认 public 继承
class D4 : Base { };        // 默认 private 继承